/*
 * Copyright (C) 2013 Michael
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package com.jm.jdbc.xport;

import com.jm.commons.ui.UIBounds;
import com.jm.jdbc.xport.objects.Database;
import com.jm.jdbc.xport.objects.Definition;
import com.jm.jdbc.xport.objects.Schema;
import com.jm.jmsql.xporta.models.DefinitionComboBoxModel;
import com.jm.jmsql.xporta.models.SchemaComboBoxModel;
import com.jm.jmsql.xporta.models.TableComboBoxModel;
import com.jm.jmsql.xporta.utils.Settings;
import com.jm.xporta.XPortException;
import com.jm.xporta.plugin.XPort;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ComboBoxModel;
import javax.swing.event.ListDataListener;
import javax.swing.filechooser.FileFilter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 *
 * @author Michael L.R. Marques
 */
public class JdbcXPorta extends javax.swing.JDialog implements XPort {
    
    //
    private ResultSet results;
    //
    private boolean done = false;
    
    /**
     * Creates new form JdbcXPorta
     */
    public JdbcXPorta() {
        super();
        initComponents();
    }
    
    /**
     * 
     * @param results 
     * @throws com.jm.xporta.XPortException 
     */
    @Override
    public void initialize(ResultSet results) throws XPortException {
        this.results = results;
        try {
            this.results.beforeFirst();
        } catch (SQLException sqle) {
            throw new XPortException(sqle);
        }
        // Set the ui bounds
        UIBounds.setBounds(this);
        // Set the icon image
        try {
            setIconImage(ImageIO.read(getClass().getClassLoader().getResource("com/jm/jmsql/icons/xport.png")));
        } catch (IOException ioe) {}
        // Set visible
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                setVisible(true);
            }
        });
        // Load in thread
        new Thread(new Runnable() {
            @Override
            public void run() {
                cbxDatabases.setModel(new DBComboBoxModel());
                // Initialize the databases event handler
                cbxDatabases.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        cbxDefinitions.removeAllItems();
                        cbxDefinitions.setModel(new DefinitionComboBoxModel((Database) e.getItem()));
                    }
                });
                // Initialize the definitions event handler
                cbxDefinitions.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        cbxSchemas.removeAllItems();
                        cbxSchemas.setModel(new SchemaComboBoxModel((Definition) e.getItem()));
                    }
                });
                // Initialize the schema event handler
                cbxSchemas.addItemListener(new ItemListener() {
                    @Override
                    public void itemStateChanged(ItemEvent e) {
                        cbxTables.removeAllItems();
                        cbxTables.setModel(new TableComboBoxModel((Schema) e.getItem()));
                    }
                });
            }
        }).start();
    }
    
    /**
     * 
     * @return 
     */
    @Override
    public String getName() {
        return "Jdbc XPort";
    }

    /**
     * 
     * @return 
     */
    @Override
    public String getDescription() {
        return "Exports data to another database definition.";
    }
    
    /**
     * 
     * @return 
     */
    @Override
    public ResultSet getData() {
        return this.results;
    }
    
    /**
     * 
     * @param output
     * @throws XPortException 
     */
    @Override
    public void setOutput(Object output) throws XPortException {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * 
     * @return 
     */
    @Override
    public Object getOutput() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * 
     * @return 
     */
    @Override
    public FileFilter[] getFileFilters() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     *
     * @param max
     */
    @Override
    public void setProgressMaximum(int max) {
        this.progress.setMaximum(max);
    }

    /**
     *
     * @param min
     */
    @Override
    public void setProgressMinimum(int min) {
        this.progress.setMinimum(min);
    }

    /**
     *
     * @param value
     */
    @Override
    public void setProgressValue(int value) {
        this.progress.setValue(value);
    }

    /**
     *
     * @return
     */
    @Override
    public int getProgressValue() {
        return this.progress.getValue();
    }
    
    /**
     * 
     * @throws XPortException 
     */
    @Override
    public void export() throws XPortException {
        try {
            
        } finally {
            this.done = true;
        }
    }
    
    /**
     * 
     * @param done 
     */
    @Override
    public void done(boolean done) {
        this.done = done;
    }
    
    /**
     * 
     * @return 
     */
    @Override
    public boolean isDone() {
        return this.done;
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new com.jm.commons.components.panel.ImagePanel();
        cbxDatabases = new com.jm.commons.components.combobox.HintJComboBox();
        cbxDefinitions = new com.jm.commons.components.combobox.HintJComboBox();
        cbxSchemas = new com.jm.commons.components.combobox.HintJComboBox();
        btnDone = new javax.swing.JButton();
        btnCancel = new javax.swing.JButton();
        cbxTables = new com.jm.commons.components.combobox.HintJComboBox();
        jScrollPane1 = new javax.swing.JScrollPane();
        tableMatching = new javax.swing.JTable();
        progress = new javax.swing.JProgressBar();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("Export to Database...");

        mainPanel.setImage(null);

        cbxDatabases.setHintText("Select a Database...");

        cbxDefinitions.setHintText("Select a Definition...");
        cbxDefinitions.setEnabled(false);

        cbxSchemas.setHintText("Select a Schema...");
        cbxSchemas.setEnabled(false);

        btnDone.setText("Done");
        btnDone.setEnabled(false);

        btnCancel.setText("Cancel");

        cbxTables.setHintText("Select a Table...");
        cbxTables.setEnabled(false);

        tableMatching.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        tableMatching.setEnabled(false);
        jScrollPane1.setViewportView(tableMatching);

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(progress, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 386, Short.MAX_VALUE)
                    .addComponent(cbxDatabases, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(cbxDefinitions, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(cbxSchemas, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                        .addGap(0, 0, Short.MAX_VALUE)
                        .addComponent(btnCancel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(btnDone))
                    .addComponent(cbxTables, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addGap(96, 96, 96)
                .addComponent(cbxDatabases, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(cbxDefinitions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(cbxSchemas, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(cbxTables, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnDone)
                    .addComponent(btnCancel))
                .addContainerGap())
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(mainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnCancel;
    private javax.swing.JButton btnDone;
    private com.jm.commons.components.combobox.HintJComboBox cbxDatabases;
    private com.jm.commons.components.combobox.HintJComboBox cbxDefinitions;
    private com.jm.commons.components.combobox.HintJComboBox cbxSchemas;
    private com.jm.commons.components.combobox.HintJComboBox cbxTables;
    private javax.swing.JScrollPane jScrollPane1;
    private com.jm.commons.components.panel.ImagePanel mainPanel;
    private javax.swing.JProgressBar progress;
    private javax.swing.JTable tableMatching;
    // End of variables declaration//GEN-END:variables
    
    /**
     * 
     */
    class DBComboBoxModel implements ComboBoxModel {
    
        //
        private List<Database> databases;
        private int index;

        /**
         * 
         */
        public DBComboBoxModel() {
            this.databases = new ArrayList();
            this.index = -1;
            // 
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            Document document = null;
            try {
                document = factory.newDocumentBuilder().parse(Settings.getDatabasesFile());
            } catch (ParserConfigurationException | XPathExpressionException | SAXException | IOException ex) {
                ex.printStackTrace();
            }
            try {
                NodeList nodeList = (NodeList) XPathFactory.newInstance().newXPath().evaluate("/databases/database", document, XPathConstants.NODESET);
                for(int i = 0; i < nodeList.getLength(); i++) {
                    Node node = nodeList.item(i);
                    if (node.getNodeName().equals("database") &&
                            node.hasAttributes()) {
                        NamedNodeMap map = node.getAttributes();
                        if (map.getNamedItem("library") == null) {
                            this.databases.add(new Database(map.getNamedItem("name").getNodeValue(), map.getNamedItem("class").getNodeValue()));
                        } else {
                            this.databases.add(new Database(map.getNamedItem("name").getNodeValue(), map.getNamedItem("class").getNodeValue(), map.getNamedItem("library").getNodeValue()));
                        }
                    }
                }
            } catch (XPathExpressionException xpee) {
                xpee.printStackTrace();
            }
        }

        /**
         * 
         * @return 
         */
        @Override
        public int getSize() {
            return this.databases.size();
        }

        /**
         * 
         * @param i
         * @return 
         */
        @Override
        public Object getElementAt(int i) {
            return this.databases.get(i);
        }

        /**
         * 
         * @param o 
         */
        @Override
        public void setSelectedItem(Object o) {
            //
            if (o instanceof Database) {
                this.index = this.databases.indexOf(o);
            } else {
                this.index = -1;
            }
        }

        /**
         * 
         * @return 
         */
        @Override
        public Object getSelectedItem() {
            if (this.index < 0) {
                return null;
            } else {
                return this.databases.get(this.index);
            }
        }

        /**
         * 
         * @param ll 
         */
        @Override
        public void addListDataListener(ListDataListener ll) {}

        /**
         * 
         * @param ll 
         */
        @Override
        public void removeListDataListener(ListDataListener ll) {}

    }
    
}
